#pragma once

#include "Thread.hpp"
#include <queue>

// template<class T>
class blockqueue
{
private:
    bool IsFull()
    {
        return _block_queue.size() == _cap;
    }

    bool IsEmpty()
    {
        return _block_queue.empty();
    }
public:
    blockqueue(int cap) : _cap(cap)
    {
        pthread_mutex_init(&_producer_mutex, nullptr);
        pthread_mutex_init(&_consumer_mutex, nullptr);

        pthread_cond_init(&_producer_cond, nullptr);
        pthread_cond_init(&_consumer_cond, nullptr);
    }

    void Enqueue(int &in) // producer
    {
        pthread_mutex_lock(&_producer_mutex);

        while (IsFull())
        {
            ++_producer_wait_num;
            pthread_cond_signal(&_consumer_cond);
            pthread_cond_wait(&_producer_cond, &_producer_mutex);
            --_producer_wait_num;
        }

        _block_queue.push(in);
        if (_consumer_wait_num > 0)
            pthread_cond_signal(&_consumer_cond);

        pthread_mutex_unlock(&_producer_mutex);
    }

    void Pop(int *out) // consumer
    {
        pthread_mutex_lock(&_consumer_mutex);
        while (IsEmpty())
        {
            ++_consumer_wait_num;
            pthread_cond_signal(&_producer_cond);
            pthread_cond_wait(&_consumer_cond, &_consumer_mutex);
            --_consumer_wait_num;
        }
        *out = _block_queue.front();
        _block_queue.pop();
        if (_producer_wait_num > 0)
            pthread_cond_signal(&_producer_cond);

        pthread_mutex_unlock(&_consumer_mutex);
    }

    ~blockqueue()
    {
        pthread_mutex_destroy(&_producer_mutex);
        pthread_mutex_destroy(&_consumer_mutex);

        pthread_cond_destroy(&_producer_cond);
        pthread_cond_destroy(&_consumer_cond);
    }

private:
    int _cap;
    queue<int> _block_queue; // 生产者生产任务, 消费者处理任务

    int _producer_wait_num = 0;
    int _consumer_wait_num = 0;

    pthread_cond_t _producer_cond; 
    pthread_cond_t _consumer_cond;

    pthread_mutex_t _producer_mutex;
    pthread_mutex_t _consumer_mutex;
};
